home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK2.toast / Development Kits (Disc 2) / ScriptX / Code Samples / untested / tcpip / ifish / connectm.sx < prev    next >
Encoding:
Text File  |  1996-05-21  |  5.5 KB  |  232 lines  |  [TEXT/ttxt]

  1. --<<
  2.  
  3. in module InternetFish
  4.  
  5. -- Connection Manager:
  6. -- It is responsible for managing connections with other instances of itself
  7. -- running on different machines. ConnectionManagers exchange [host,port]
  8. -- information so each CM can be connected to all other CMs
  9.  
  10. class ConnectionManager ()
  11. instance variables
  12.     -- array of connections
  13.     connections : (new array)
  14.     client
  15.     tcpListen
  16.     myPort
  17. end
  18.  
  19. method init self {object connectionManager} #key port: port client: client -> (
  20.     self.client := client
  21.     self.myPort := port
  22.     addconnection self (new connection host: (getIPAddress tcpstream) port: port client: self)
  23.     self.tcplisten := new tcpstream port: port listen: true
  24.     startListening self &
  25. )
  26.  
  27. method findConnection self {object ConnectionManager} stream -> (
  28.     for c in self.connections do
  29.         if c.tcpStream = stream do
  30.             return c
  31.     undefined
  32. )
  33.  
  34. method findConnectionForHostPort self {object ConnectionManager} host port -> (
  35.     for c in self.connections do
  36.         if c.host = host and c.port = port do
  37.             return c
  38.     undefined
  39. )
  40.  
  41. method removeConnection self {object ConnectionManager} c ->
  42.     deleteOne self.connections c
  43.  
  44. method addConnection self {object ConnectionManager} c -> (
  45.     append self.connections c
  46.     noteNewConnection self.client c (size self.connections = 2)
  47. )
  48.  
  49. global rnd := new randomState
  50.  
  51. method chooseConnection self {class ConnectionManager} -> (
  52.     local n := (size self.connections)
  53.     local i := random rnd (n - 1)
  54.     i := i + 2
  55.     for j in 2 to n do (
  56.         if i > n do i := 2
  57.         local c := self.connections[i]
  58.         if c.tcpstream != undefined do (
  59.             return c
  60.         )
  61.         
  62.         i := i + 1
  63.     )
  64.     -- Are there any connections we can open?
  65.     -- If not we have no one to talk to! 
  66.     return undefined
  67. )
  68.  
  69.  
  70.  
  71. method isKnownAbout self {class ConnectionManager} addr port -> (
  72.     for i in self.connections do 
  73.         if i.host = addr and i.port = port do return true
  74.     return false
  75. )
  76.  
  77. function readPort s -> (
  78.     local a := read s
  79.     local b := read s
  80.     a * 256 + b
  81. )
  82.  
  83. function writePort s p -> (
  84.     local a := (p/256) as integer
  85.     local b := mod p 256
  86.     write s a
  87.     write s b
  88. )
  89.  
  90. function writeIPAddress s addr -> (
  91.     for i in addr do write s i
  92. )
  93.  
  94. function readIPAddress s  -> (
  95.     local addr := new quad
  96.     for i in 1 to 4 do addr[i] := read s
  97.     addr
  98. )
  99.  
  100. method connectTo self {class ConnectionManager} host port -> (
  101.     connectToServer self host port
  102. )
  103.     
  104. method connectToSomeMore self {object ConnectionManager} -> (
  105.     local i := 2
  106.     repeat while i <= (size self.connections) do (
  107.         local c := self.connections[i]
  108.         if c.tcpstream = undefined then (
  109.             guard (
  110.                 connectConnectionToServer self c
  111.                 i := i + 1
  112.             )
  113.             catching        
  114.                 TCPException: (caught (removeConnection self c))
  115.                 --? Perhaps we get a cantread/write error also?
  116.             end
  117.         ) else
  118.             i := i + 1
  119.     )
  120. )
  121.  
  122. method talkToServer self {object ConnectionManager} s -> (
  123.     writePort s self.myPort
  124.     writeKnownAbout self s
  125.     readKnownAbout self s
  126. )
  127.  
  128. method connectToServer self {object ConnectionManager}  server port -> (
  129.     -- Create a connection and open it
  130.     -- This is contorted because we don't have a way of getting the ipaddress
  131.     local s := new tcpstream host: server port: port
  132.     local con := new connection client: self host: s.ipAddress port: port
  133.     -- Assumes that we don't have a connection already
  134.     addconnection self con
  135.     completeConnection self con s
  136. )
  137.  
  138. method connectConnectionToServer self {object ConnectionManager} con -> (
  139.     --- Open an existing connection
  140.     local s := new tcpstream host: con.host port: con.port
  141.     completeConnection self con s
  142. )
  143.  
  144. method completeConnection self {object ConnectionManager} con s -> (
  145.     talkToServer self s
  146.     openConnection con s
  147.     con
  148. )
  149.  
  150. method writeKnownAbout self {object ConnectionManager} s -> (
  151.     -- This could change
  152.     write s (size self.connections)
  153.     for i in self.connections do (
  154.         writeIPAddress s i.host
  155.         writePort s i.port
  156.     )
  157.     flush s
  158. )
  159.  
  160. method readKnownAbout self {object ConnectionManager} s -> (
  161.     local n := read s
  162.     for i in 1 to n do (
  163.         local addr := readIPAddress s
  164.         local port := readPort s
  165.         if not (isKnownAbout self addr port) do
  166.           addconnection self (new connection host: addr port: port client: self)
  167.     )
  168. )
  169.  
  170. method establishConnection self {object ConnectionManager} s -> (
  171.     local port := readport s
  172.     local host := s.ipaddress
  173.     local c := findConnectionForHostPort self  host port
  174.     if c = undefined do (
  175.         c := (new connection client: self host: host port: port)
  176.         addconnection self c
  177.     )
  178.     -- This assumes that we don't already have a connection
  179.     readKnownAbout self s
  180.     writeKnownAbout self s
  181.     openConnection c s
  182. )
  183.  
  184. method startListening self {object ConnectionManager} -> (
  185.     repeat while true do (
  186.         local s := accept self.tcplisten
  187.         establishConnection self s &
  188.     )
  189. )
  190.  
  191. method handleMessage self {object ConnectionManager} obj -> (
  192.     if isakindof obj array do (
  193.         if obj[1] = @readFailed then (
  194.             handleReadError self obj[2]
  195.         )
  196.         else if obj[1] = @writeFailed then (
  197.             handleWriteError self obj[2]
  198.         )
  199.         else  
  200.             handleNormalMessage self.client obj
  201.     )
  202. )
  203.  
  204. method handleWriteError self {object ConnectionManager} stream -> (
  205.     handleDisconnect self stream
  206. )
  207.  
  208. method handleReadError self {object ConnectionManager} stream -> (
  209.     handleDisconnect self stream
  210. )
  211.  
  212. method handleDisconnect self {object ConnectionManager} stream -> (
  213.     local c := findConnection self stream
  214.     removeConnection self c
  215.     noteLostConnection self.client c
  216. )
  217.  
  218. method disconnect self {object ConnectionManager} -> (
  219.     local x := new array
  220.     addmany x self.connections
  221.     for c in x do 
  222.         if c.tcpstream != undefined do (
  223.             -- This will cause errors which will cause the right thing to happen
  224.             plug c.tcpstream
  225.             c.tcpstream := undefined
  226.         )
  227. )
  228.  
  229. method stopListening self {object ConnectionManager} ->
  230.     plug self.tcplisten
  231.  
  232.